#include "serv_network.h"

using namespace std;

Network::Network()
{
	// Loads the maps
	int t_numberOfMaps = 0;

    ifstream f_list("../../data/maps/list.txt", ios::in);

    if(f_list)
    {
        f_list >> t_numberOfMaps;

        f_list.close();
    }

    cout << "Loading " << t_numberOfMaps << " maps... ";
    for (int i=0; i<t_numberOfMaps; i++)
    {
        Maps Map;
        Map.LoadMap(i);
        m_mapsVector.push_back(Map);
    }

    cout << "Done!" << endl;
}

// Connect to the database and start the server
void Network::Connect()
{
	// Connect to the database
	try {
		driver = get_driver_instance();
		con = driver->connect("tcp://127.0.0.1:3306", "mmorpg", "b682GwHrcCac8JeC");
		stmt = con->createStatement();
		stmt->execute("USE mmorpg");

	} catch (sql::SQLException &e) {
	  
		cout << "WARNING : Could not connect to the database, on tcp://127.0.0.1:3306" << endl;
	}

    if (!m_listener.Listen(23278))
        cout << "Couldn't listen to port 23278" << endl;
	else
		cout << "Listening to port 23278, waiting for connections..." << endl;

    m_selector.Add(m_listener);

	m_socketList.push_back(m_listener);

	m_status = true;
}

// Close the server
void Network::Close()
{
	NewQuery("UPDATE `user` SET islogged=0 WHERE islogged>0");
	NewQuery("UPDATE `char` SET islogged=0 WHERE islogged>0");
}

// \return the status of the server
bool Network::status()
{
	return m_status;
}

// Set the status of the server
void Network::SetStatus(bool status)
{
	m_status = status;
}

// Refresh the state of the server
void Network::Refresh()
{
	int numberOfSockets = m_selector.Wait();
    for (int i=0; i<numberOfSockets; ++i)
    {
        sf::SocketTCP socket = m_selector.GetSocketReady(i);

        if (socket == m_listener)
        {
            // If the listening socket is ready, it means that we can accept a new connection
            sf::IPAddress address;
            sf::SocketTCP client;
            m_listener.Accept(client, &address);

            // Add it to the selector and the vectors
            m_selector.Add(client);
            m_socketList.push_back(client);

			stringstream ss;
			ss << "client-id=" << m_socketList.size()-1 << ";newversion=" << "v0.0.0004" << ";";

            sf::Packet Packet;
            Packet << 0 << "" << "" << ss.str();
            client.Send(Packet);

            cout << "New client connected.  (" << address << ") (ID " << m_socketList.size()-1 << ")" << endl;
        }
        else
        {
            // Else, it is a client socket so we can read the data he sent
            sf::Packet packet;
            if (socket.Receive(packet) == sf::Socket::Done)
            {
                struct functions packetInformation;

                if (!(packet >> packetInformation.id >> packetInformation.function >> packetInformation.argument >> packetInformation.variable))
					cout << "Packet reading error." << endl;
				else 
					m_packetsToReceive.push(packetInformation);

            }
			// Error with the socket, remove from list
            else
                m_selector.Remove(socket);
			
        }
    }
}

// Look if any packets was received
void Network::ReceivePackets()
{
	if (m_packetsToReceive.size() != 0)
	{
		struct functions packetInformation = m_packetsToReceive.front();
		m_packetsToReceive.pop();

		if (packetInformation.function == "disconnect")
			Disconnect(packetInformation.id);

		if (packetInformation.function == "login")
			Login(packetInformation.id, packetInformation.argument, packetInformation.variable);

		if (packetInformation.function == "selectchar")
			SelectChar(packetInformation.id, packetInformation.argument);

		if(packetInformation.function == "message")
			Message(packetInformation.id, packetInformation.variable);

		if (packetInformation.function == "move")
			Move(packetInformation.id, atoi(packetInformation.argument.c_str()), atoi(packetInformation.variable.c_str()));

		if (packetInformation.function == "nextmove")
			NextMove(packetInformation.id);
	}
}

// Send packets
void Network::SendPackets()
{
	if (m_packetsToSend.size() != 0)
	{
		struct functions packetInformation = m_packetsToSend.front();
		m_packetsToSend.pop();

		sf::Packet packet;

		packet << packetInformation.id << packetInformation.function << packetInformation.argument << packetInformation.variable;

		if (m_socketList[packetInformation.id].Send(packet) != sf::Socket::Done)
		{
			Network::Disconnect(packetInformation.id);
		}
	}
}

// Send a new packet
void Network::NewPacket(int id, std::string function, std::string argument, std::string variable)
{
	struct functions packetInformation;

	packetInformation.id = id;
	packetInformation.function = function;
	packetInformation.argument = argument;
	packetInformation.variable = variable;

	m_packetsToSend.push(packetInformation);
}

// Send a new update query
void Network::NewQuery(std::string query)
{
	try {

	stmt->executeQuery(query);

	} catch (sql::SQLException &e) {
	  /*cout << "# ERR: SQLException in " << __FILE__;
	  cout << "(" << __FUNCTION__ << ") on line " 
		 << __LINE__ << endl;
	  cout << "# ERR: " << e.what();
	  cout << " (MySQL error code: " << e.getErrorCode();
	  cout << ", SQLState: " << e.getSQLState() << " )" << endl;*/
	}
}

// Ping all the clients
void Network::Ping()
{
	for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
	{
		struct functions packetInformation = {m_charid[it->second.charname], "p", "p", "p"};
		m_packetsToSend.push(packetInformation);
	}
}

// If user wanna login
void Network::Login(int id, std::string username, std::string password)
{
	//try {

	bool canLogin = false;

	sql::ResultSet *res;

	// Check if the user and the password matches, and if the user is not logged already
	ostringstream ss;
	ss << "SELECT id FROM user WHERE username='" << username << "' AND password='" << password << "' AND islogged=0";
	res = stmt->executeQuery(ss.str());
	if (res->next())
	{
		canLogin = true;
	}

	if (!canLogin)
	{
		struct functions packetInformation = {id, "login", "refuse", ""};
		m_packetsToSend.push(packetInformation);

	} else {

		cout << "User " << username << " logged in. (ID " << id << ")" << endl;

		// Update the user's temp id
		ostringstream ss4;
		ss4 << "UPDATE `user` SET `islogged`='" << id << "' WHERE username='" << username << "'";
		NewQuery(ss4.str());

		ostringstream ss2;
		ss2 << "SELECT charslot1, charslot2, charslot3 FROM user WHERE islogged='" << id << "'";
		res = stmt->executeQuery(ss2.str());
		res->next();

		// Send the name of the 3 chars
		for (int i=1; i<4; i++)
		{	
			ostringstream numss;
			numss << "charslot" << i;
			int charid = res->getInt(numss.str());
			if (charid != 0)
			{
				sql::ResultSet *res2;

				ostringstream ss3;
				ss3 << "SELECT charname FROM `char` WHERE id=" << charid << "";
				res2 = stmt->executeQuery(ss3.str());
				res2->next();

				string charname = res2->getString("charname");

				stringstream ssc;
				ssc << "charname" << i << "=" << charname << ";";

				struct functions packetInformation = {id, "", "", ssc.str()};
				m_packetsToSend.push(packetInformation);

				delete res2;

			} else {

				stringstream ssc;
				ssc << "charname" << i << "=-;";

				struct functions packetInformation = {id, "", "", ssc.str()};
				m_packetsToSend.push(packetInformation);
			}
		}

		struct functions packetInformation = {id, "login", "accept", ""};
		m_packetsToSend.push(packetInformation);
	}

	delete res;

	/*} catch (sql::SQLException &e) {
	  cout << "# ERR: SQLException in " << __FILE__;
	  cout << "(" << __FUNCTION__ << ") on line " 
		 << __LINE__ << endl;
	  cout << "# ERR: " << e.what();
	  cout << " (MySQL error code: " << e.getErrorCode();
	  cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}*/
}

// If user selected a char
void Network::SelectChar(int id, std::string slot)
{
	//try {

	sql::ResultSet *res;

	// Get the id of the char selected
	ostringstream ss;
	ss << "SELECT charslot1, charslot2, charslot3 FROM user WHERE islogged=" << id;
	res = stmt->executeQuery(ss.str());
	res->next();
	
	int charid = 0;
	if (slot == "1") charid = res->getInt("charslot1");
	if (slot == "2") charid = res->getInt("charslot2");
	if (slot == "3") charid = res->getInt("charslot3");

	if (charid > 0)
	{
		// Update the char's temp id
		ostringstream ss3;
		ss3 << "UPDATE `char` SET `islogged`='" << id << "' WHERE id='" << charid << "'";
		NewQuery(ss3.str());

		// Send the char's info to the client
		ostringstream ss2;
		ss2 << "SELECT * FROM `char` WHERE id=" << charid;
		res = stmt->executeQuery(ss2.str());
		res->next();

		character charinfo;
		charinfo.charname = res->getString("charname");
		charinfo.map = res->getInt("map");
		charinfo.x = res->getInt("x");
		charinfo.y = res->getInt("y");
		charinfo.rank = res->getInt("rank");
		for (int i=0; i<12; i++)
		{
			std::stringstream ss;
			ss << "e_" << i;
			charinfo.equip.push_back(res->getInt(ss.str()));
		}
		m_charInfo[id] = charinfo;
		m_charid[charinfo.charname] = id;

		cout << "Character " << charinfo.charname << " has entered the world. (ID " << id << ")" << endl;

		// Send info to the client
		struct functions packetInformationLoadmap = {id, "selectchar", "loadmap", ""};
		m_packetsToSend.push(packetInformationLoadmap);

		stringstream ssNewmapInfo;
		ssNewmapInfo << "map-id=" << charinfo.map << ";char-pos-x=" << charinfo.x << ";char-pos-y=" << charinfo.y << ";charname=" << charinfo.charname << ";";
		struct functions packetInformationNewmapInfo = {id, "", "", ssNewmapInfo.str()};
		m_packetsToSend.push(packetInformationNewmapInfo);

		struct functions packetInformationLoadmap2 = {id, "main", "loadmap", ""};
		m_packetsToSend.push(packetInformationLoadmap2);

		struct functions packetInformationMOTD = {id, "message", "server", "MOTD: Thank you for testing! Please report any bugs, and we will do our best to squish it."};
		m_packetsToSend.push(packetInformationMOTD);

		// Send equips
		ostringstream sse;
		for (int i=0; i<12; i++)
			sse << m_charInfo[id].equip[i] << "n";

		struct functions packetInformationEquip = {id, "items", "equips", sse.str()};
		m_packetsToSend.push(packetInformationEquip);

		// Send items
		ostringstream ssi;
		ostringstream ss6;
		ss6 << "SELECT itemid, quantity, invid FROM `inventory` WHERE charid=" << charid;
		res = stmt->executeQuery(ss6.str());
		while (res->next())
		{
			ssi << res->getInt("quantity") << "i" << res->getInt("itemid") << "a" << res->getInt("invid") << "n";
		}
		ssi << "e";
		struct functions packetInformationItems = {id, "items", "inventory", ssi.str()};
		m_packetsToSend.push(packetInformationItems);


		/*struct QueuedItem ToSendParty = {ToReceive.ToID, "", "updateparty", "name", party, 0, 0, 0};
		QueueToSend.push(ToSendParty);

		struct QueuedItem ToSendHp = {ToReceive.ToID, "", "updatestat", "hp", "", res->getInt("hp"), res->getInt("maxhp"), 0};
		QueueToSend.push(ToSendHp);

		struct QueuedItem ToSendMp = {ToReceive.ToID, "", "updatestat", "mp", "", res->getInt("mp"), res->getInt("maxmp"), 0};
		QueueToSend.push(ToSendMp);*/

		// Send info to clients
		stringstream firstInfo;
		firstInfo << id << ";" << m_charInfo[id].x << ";" << m_charInfo[id].y << ";" << m_charInfo[id].charname << ";" << m_charInfo[id].equip[0] << ";" << m_charInfo[id].equip[2] << ";";
		for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
		{
			if (it->second.map == m_charInfo[id].map && it->second.charname != m_charInfo[id].charname)
			{
				// Send info of everyone on the map to client
				stringstream inInfo;
				inInfo << m_charid[it->second.charname] << ";" << it->second.x << ";" << it->second.y << ";" << it->second.charname << ";" << it->second.equip[0] << ";" << it->second.equip[2] << ";";
				struct functions packetInformation = {id, "main", "charin", inInfo.str()};
				m_packetsToSend.push(packetInformation);

				// Send info of client logging in to everyone on the map
				struct functions packetInformation2 = {m_charid[it->second.charname], "main", "charin", firstInfo.str()};
				m_packetsToSend.push(packetInformation2);
			}
		}

		/*
		// Send info to party members
		if (party != "-")
		{
			ostringstream ss4;
			ss4 << "SELECT islogged FROM `char` WHERE islogged>0 AND party='" << party << "'";
			res = stmt->executeQuery(ss4.str());
			while (res->next())
			{
				if (res->getInt("islogged") != ToReceive.ToID)
				{
					struct QueuedItem ToSend = {res->getInt("islogged"), charname, "updateparty", "login", "", 0, 0, 0};
					QueueToSend.push(ToSend);
				}

				struct QueuedItem ToSend = {ToReceive.ToID, charname, "updateparty", "join", "", 0, 0, 0};
				QueueToSend.push(ToSend);
			}
		}*/

		// Creates the path vector (void for the unknown ids)
		int t_numVoid = id - m_charPath.size() + 1;
		for (int i=0; i<t_numVoid; i++)
		{
			vector<Node> t_vect;
			m_charPath.push_back(t_vect);
		}
	}

	delete res;

	/*} catch (sql::SQLException &e) {
	  cout << "# ERR: SQLException in " << __FILE__;
	  cout << "(" << __FUNCTION__ << ") on line " 
		 << __LINE__ << endl;
	  cout << "# ERR: " << e.what();
	  cout << " (MySQL error code: " << e.getErrorCode();
	  cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}*/
}

// If a user sent a message
void Network::Message(int id, std::string message)
{
	if (message.size() < 1)
		return;

    // If the message was not a command
    if (message[0] != '!' && message[0] != '/')
    {
		for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
		{
			if (it->second.map == m_charInfo[id].map)
			{
				struct functions packetInformation = {m_charid[it->second.charname], "message", m_charInfo[id].charname, message};
				m_packetsToSend.push(packetInformation);
			}
		}

    } else {
		
        // If the message was a command
        size_t t_firstSpace;
        t_firstSpace = message.find(" ");
        string t_functionType = message.substr(1, t_firstSpace - 1);

        // WHISPER
        if (t_functionType == "w")
        {
            size_t t_secondSpace;
            t_secondSpace = message.find(" ", t_firstSpace + 1);
            string t_username = message.substr(t_firstSpace + 1, t_secondSpace - 3);
            string t_messageSent = message.substr(t_secondSpace + 1, message.size() - t_secondSpace);

			bool isOnline = false;

			for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
			{
				if (it->second.charname == t_username)
				{
					std::stringstream fromChat;
					fromChat << "[From " << m_charInfo[id].charname << "] " << t_messageSent;

					struct functions packetInformation = {m_charid[it->second.charname], "message", "whisper", fromChat.str()};
					m_packetsToSend.push(packetInformation);

					std::stringstream toChat;
					toChat << "[To " << it->second.charname << "] " << t_messageSent;

					struct functions packetInformation2 = {id, "message", "whisper", toChat.str()};
					m_packetsToSend.push(packetInformation2);

					isOnline = true;
				}
			} 
		
			if (!isOnline)
			{
				struct functions packetInformation = {id, "message", "server", "Char doesn't exist or not online."};
				m_packetsToSend.push(packetInformation);
            }

        // GLOBAL TALK (All maps)
        } else if (t_functionType == "g")
        {
            if (m_charInfo[id].rank > 1)
            {
                string t_messageSent = message.substr(t_firstSpace + 1, message.size() - t_firstSpace);
				std::stringstream ss;
				ss << "[Global] " << m_charInfo[id].charname << " : " << t_messageSent;

				for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
				{
					struct functions packetInformation = {m_charid[it->second.charname], "message", "global", ss.str()};
					m_packetsToSend.push(packetInformation);
				}

            } else {

				struct functions packetInformation = {id, "message", "server", "Your rank is not high enough."};
				m_packetsToSend.push(packetInformation);
            }

		// HELP COMMAND
		} else if (t_functionType == "help")
        {
			struct functions packetInformation = {id, "message", "server", "List of commads: /help, /w, /p, /createp, /leavep, /invitep, /joinp"};
			m_packetsToSend.push(packetInformation);

			
        // PARTY CHAT
        } /*else if (t_functionType == "p")
        {
            if (party != "-")
            {
                string t_messageSent = t_message.substr(t_firstSpace + 1, t_message.size() - t_firstSpace);

				ostringstream ss4;
				ss4 << "SELECT islogged FROM `char` WHERE islogged>0 AND party='" << party << "'";
				res = stmt->executeQuery(ss4.str());
				while (res->next())
				{
					struct QueuedItem ToSend = {res->getInt("islogged"), ToReceive.Username, "message", "party", t_messageSent, 0, 0, 0};
                    QueueToSend.push(ToSend);
				}

			// If not already in a party
            } else {

                struct QueuedItem ToSend = {ToReceive.ToID, ToReceive.Username, "message", "server", "Currently not in any party.", 0, 0, 0};
                QueueToSend.push(ToSend);
            }

        // CREATE PARTY
        } else if (t_functionType == "createp")
        {
            // If not already in a party
            if (party == "-")
            {
                size_t t_secondSpace;
                t_secondSpace = t_message.find(" ", t_firstSpace + 1);
                string t_partyName = t_message.substr(t_firstSpace + 1, t_secondSpace - 9);

				ostringstream ss4;
				ss4 << "SELECT id FROM `char` WHERE party='" << t_partyName << "'";
				res = stmt->executeQuery(ss4.str());

				if (res->next())
				{
					// Party name already exists...
					struct QueuedItem ToSendMess = {ToReceive.ToID, "", "message", "server", "Party name unavailable. Please try again !", 0, 0, 0};
                    QueueToSend.push(ToSendMess);
                
                } else {

                    ostringstream t_chatStream;
                    t_chatStream << "Party '" << t_partyName << "' created !";
                    string t_chatText = t_chatStream.str();

                    // Create party
                    struct QueuedItem ToSendMess = {ToReceive.ToID, "", "message", "server", t_chatText, 0, 0, 0};
                    QueueToSend.push(ToSendMess);

                    struct QueuedItem ToSendParty = {ToReceive.ToID, "", "updateparty", "name", t_partyName, 0, 0, 0};
                    QueueToSend.push(ToSendParty);

					ostringstream ss;
					ss << "UPDATE `char` SET party='" << t_partyName << "' WHERE islogged='" << ToReceive.ToID << "'";
					NewQuery(stmt, ss.str());

					ostringstream ss3;
					ss3 << "SELECT islogged FROM `char` WHERE islogged>0 AND map=" << map;
					res = stmt->executeQuery(ss3.str());
					while (res->next())
					{
						if (res->getInt("islogged") != ToReceive.ToID)
						{
							struct QueuedItem ToSendParty2 = {res->getInt("islogged"), charname, "updateparty", "oname", t_partyName, 0, 0, 0};
							QueueToSend.push(ToSendParty2);
						}
					}
                }

            } else {

                // Already in a party...
                struct QueuedItem ToSend = {ToReceive.ToID, "", "message", "server", "Already in a party.", 0, 0, 0};
                QueueToSend.push(ToSend);
            }

        // LEAVE PARTY
        } else if (t_functionType == "leavep")
        {
            if (party == "-")
            {
                struct QueuedItem ToSend = {ToReceive.ToID, "", "message", "server", "Currently not in any party.", 0, 0, 0};
                QueueToSend.push(ToSend);

            } else {

				ostringstream ss4;
				ss4 << "SELECT islogged FROM `char` WHERE islogged>0 AND party='" << party << "'";
				res = stmt->executeQuery(ss4.str());
				while (res->next())
				{					
					struct QueuedItem ToSend = {res->getInt("islogged"), ToReceive.Username, "updateparty", "leave", "", 0, 0, 0};
                    QueueToSend.push(ToSend);
				}

                ostringstream t_chatStream;
                t_chatStream << "Left party '" << party << "' !";
                string t_chatText = t_chatStream.str();

                // Leave party
                struct QueuedItem ToSendMess = {ToReceive.ToID, "", "message", "server", t_chatText, 0, 0, 0};
                QueueToSend.push(ToSendMess);

                struct QueuedItem ToSendParty = {ToReceive.ToID, "", "updateparty", "name", "-", 0, 0, 0};
                QueueToSend.push(ToSendParty);

				ostringstream ss;
				ss << "UPDATE `char` SET party='" << "-" << "' WHERE islogged='" << ToReceive.ToID << "'";
				NewQuery(stmt, ss.str());

				ostringstream ss3;
				ss3 << "SELECT islogged FROM `char` WHERE islogged>0 AND map=" << map;
				res = stmt->executeQuery(ss3.str());
				while (res->next())
				{
					if (res->getInt("islogged") != ToReceive.ToID)
					{
						struct QueuedItem ToSendParty2 = {res->getInt("islogged"), charname, "updateparty", "oname", "-", 0, 0, 0};
                        QueueToSend.push(ToSendParty2);
					}
				}
            }

        // INVITE SOMEONE TO PARTY
        } else if (t_functionType == "invitep")
        {
            if (party != "-")
            {
                size_t t_secondSpace;
                t_secondSpace = t_message.find(" ", t_firstSpace + 1);
                string t_charname = t_message.substr(t_firstSpace + 1, t_secondSpace - 9);

				ostringstream ss3;
				ss3 << "SELECT islogged, party FROM `char` WHERE islogged>0 AND charname='" << t_charname << "'";
				res = stmt->executeQuery(ss3.str());
				if (res->next())
				{
					if (res->getString("party") == "-")
                    {
                        ostringstream t_chatStream;
                        t_chatStream << "Invite to party '" << party << "', type /joinp to accept.";
                        string t_chatText = t_chatStream.str();

                        struct QueuedItem ToSend = {res->getInt("islogged"), "", "message", "server", t_chatText, 0, 0, 0};
                        QueueToSend.push(ToSend);

                        struct QueuedItem ToSend2 = {ToReceive.ToID, "", "message", "server", "Invite sent.", 0, 0, 0};
                        QueueToSend.push(ToSend2);

                        ostringstream ss;
						ss << "UPDATE `char` SET iparty='" << party << "' WHERE islogged='" << res->getInt("islogged") << "'";
						NewQuery(stmt, ss.str());

                    // Char already in a party
                    } else {

                        struct QueuedItem ToSend = {ToReceive.ToID, "", "message", "server", "Char already in a party.", 0, 0, 0};
                        QueueToSend.push(ToSend);
                    }

				} else {

					// Char doesn't exist / offline...
                    struct QueuedItem ToSend = {ToReceive.ToID, "", "message", "server", "Char doesn't exist or not online.", 0, 0, 0};
                    QueueToSend.push(ToSend);
                }                

            // Not in a party...
            } else {

                struct QueuedItem ToSendMess = {ToReceive.ToID, "", "message", "server", "Currently not in any party.", 0, 0, 0};
                QueueToSend.push(ToSendMess);
            }

        // ACCEPT A PARTY INVITE
        } else if (t_functionType == "joinp")
        {
            if (iparty != "-" && party == "-")
            {
				int partysize = 0;
				ostringstream ss4;
				ss4 << "SELECT islogged FROM `char` WHERE party='" << iparty << "'";
				res = stmt->executeQuery(ss4.str());
				while (res->next())
				{					
					partysize++;
				}

                if (partysize < 8)
                {
                    ostringstream t_chatStream;
                    t_chatStream << "Party '" << iparty << "' joined !";
                    string t_chatText = t_chatStream.str();

                    struct QueuedItem ToSendMess = {ToReceive.ToID, "", "message", "server", t_chatText, 0, 0, 0};
                    QueueToSend.push(ToSendMess);

                    struct QueuedItem ToSendParty = {ToReceive.ToID, "", "updateparty", "name", iparty, 0, 0, 0};
                    QueueToSend.push(ToSendParty);

					ostringstream ss3;
					ss3 << "SELECT islogged, charname FROM `char` WHERE party='" << iparty << "'";
					res = stmt->executeQuery(ss3.str());
					while (res->next())
					{
						if (res->getInt("islogged") > 0)
                        {
                            struct QueuedItem ToSend = {res->getInt("islogged"), ToReceive.Username, "updateparty", "join", "", 0, 0, 0};
                            QueueToSend.push(ToSend);
                        }

						struct QueuedItem ToSend = {ToReceive.ToID, res->getString("charname"), "updateparty", "join", iparty, 0, 0, 0};
                        QueueToSend.push(ToSend);
					}

					ostringstream ss;
					ss << "UPDATE `char` SET party='" << iparty << "' WHERE islogged='" << ToReceive.ToID << "'";
					NewQuery(stmt, ss.str());

					ostringstream ss5;
					ss5 << "SELECT islogged FROM `char` WHERE islogged>0 AND map=" << map;
					res = stmt->executeQuery(ss5.str());
					while (res->next())
					{
						if (res->getInt("islogged") != ToReceive.ToID)
						{
							struct QueuedItem ToSendParty2 = {res->getInt("islogged"), charname, "updateparty", "oname", iparty, 0, 0, 0};
							QueueToSend.push(ToSendParty2);
						}
					}

                // Party size
                } else {

                    struct QueuedItem ToSendMess = {ToReceive.ToID, "", "message", "server", "Party size limit reached. Cannot join.", 0, 0, 0};
                    QueueToSend.push(ToSendMess);
                }
            }
        }*/
    }
}

// If a user is moving, find the path
void Network::Move(int id, int x, int y)
{
	bool CanMove = m_mapsVector[m_charInfo[id].map].FindPath(m_charInfo[id].x, m_charInfo[id].y, x, y, m_charPath[id]);

	if (!CanMove)
	{
		struct functions packetInformation = {id, "main", "donemove", ""};
		m_packetsToSend.push(packetInformation);
	}
}

// Send the next move in the path
void Network::NextMove(int id)
{
	if (m_charPath[id].size() != 0)
	{
		bool isDone = false;
		if (m_charPath[id].size() == 1) isDone = true;

		std::stringstream ss;
		ss << m_charPath[id][0].dir << ";" << m_charInfo[id].x << ";" << m_charInfo[id].y << ";";
		struct functions packetInformation = {id, "main", "move", ss.str()};
		m_packetsToSend.push(packetInformation);

		if (isDone)
		{
			struct functions packetInformationDone = {id, "main", "donemove", ""};
			m_packetsToSend.push(packetInformationDone);
		}

		// Send info to clients of the same map
		stringstream firstInfo;
		firstInfo << id << ";" << m_charPath[id][0].dir << ";" << m_charInfo[id].x << ";" << m_charInfo[id].y << ";";
		for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
		{
			if (it->second.map == m_charInfo[id].map && it->second.charname != m_charInfo[id].charname)
			{
				// Send info of client logging in to everyone on the map
				struct functions packetInformation2 = {m_charid[it->second.charname], "main", "charmove", firstInfo.str()};
				m_packetsToSend.push(packetInformation2);
			}
		}

		m_charInfo[id].x = m_charPath[id][0].x;
		m_charInfo[id].y = m_charPath[id][0].y;

        if (isDone)
		{
			int teleID = m_mapsVector[m_charInfo[id].map].GetTeleportationID(m_charPath[id][0].x, m_charPath[id][0].y);

			if (teleID != -1)
			{
				int newMapID = m_mapsVector[m_charInfo[id].map].GetTeleMap(teleID);
				int newMapX = m_mapsVector[m_charInfo[id].map].GetTeleX(teleID);
				int newMapY = m_mapsVector[m_charInfo[id].map].GetTeleY(teleID);

				stringstream ssNewmapInfo;
				ssNewmapInfo << "map-id=" << newMapID << ";char-pos-x=" << newMapX << ";char-pos-y=" << newMapY << ";";
				struct functions packetInformationNewmapInfo = {id, "", "", ssNewmapInfo.str()};
				m_packetsToSend.push(packetInformationNewmapInfo);

				struct functions packetInformationLoadmap2 = {id, "main", "loadmap", ""};
				m_packetsToSend.push(packetInformationLoadmap2);

				// Send info to chars of the old map
				for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
				{
					if (it->second.map == m_charInfo[id].map)
					{
						stringstream idstring;
						idstring << id;
						struct functions packetInformation = {m_charid[it->second.charname], "main", "charout", idstring.str()};
						m_packetsToSend.push(packetInformation);
					}
				}

				// Send info from/to chars of the new map
				stringstream firstInfo;
				firstInfo << id << ";" << newMapX << ";" << newMapY << ";" << m_charInfo[id].charname << ";" << m_charInfo[id].equip[0] << ";" << m_charInfo[id].equip[2] << ";";
				for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
				{
					if (it->second.map == newMapID && it->second.charname != m_charInfo[id].charname)
					{
						// Send info of everyone on the map to client
						stringstream inInfo;
						inInfo << m_charid[it->second.charname] << ";" << it->second.x << ";" << it->second.y << ";" << it->second.charname << ";" << it->second.equip[0] << ";" << it->second.equip[2] << ";";
						struct functions packetInformation = {id, "main", "charin", inInfo.str()};
						m_packetsToSend.push(packetInformation);

						// Send info of client logging in to everyone on the map
						struct functions packetInformation2 = {m_charid[it->second.charname], "main", "charin", firstInfo.str()};
						m_packetsToSend.push(packetInformation2);
					}
				}

				// Update the database
				m_charInfo[id].map = newMapID;
				m_charInfo[id].x = newMapX;
				m_charInfo[id].y = newMapY;
			}
		}

		// Erase the current path step
		m_charPath[id].erase(m_charPath[id].begin());
	}
}
/*
// (un)equip/move an item
void Network::UpdateItem(std::queue<struct QueuedItem> &QueueToSend, struct QueuedItem ToReceive, std::vector<int> &ClientStatusVector, std::vector<int> &ClientIDVector, sql::Statement *stmt)
{
	try {

	sql::ResultSet *res;

	ostringstream ss;
	ss << "SELECT id, charname, map FROM `char` WHERE islogged=" << ToReceive.ToID;
	res = stmt->executeQuery(ss.str());
	res->next();
	int charid = res->getInt("id");
	int mapid = res->getInt("map");
	string charname = res->getString("charname");

	string equip[] = {"e_head", "", "e_cape", "e_hand1", "", "e_hand2", "e_necklace", "e_body", "e_acc1", "e_boots", "e_belt", "e_acc2"};

	int toType = atoi(ToReceive.Argument2.c_str());
	int toID = ToReceive.Argument3;
	int fromType = ToReceive.Argument4;
	int fromID = ToReceive.Argument5;

	// From inventory to inventory (move)
	if (fromType == 2 && toType == 2)
	{
		ostringstream ss1;
		ss1 << "SELECT * FROM `inventory` WHERE charid=" << charid << " AND invid=" << fromID;
		res = stmt->executeQuery(ss1.str());
		res->next();
		int fromQty = res->getInt("quantity");
		int fromItem = res->getInt("itemid");

		ostringstream ss2;
		ss2 << "SELECT * FROM `inventory` WHERE charid=" << charid << " AND invid=" << toID;
		res = stmt->executeQuery(ss2.str());
		// If item is at 'to' location
		if (res->next())
		{
			int toQty = res->getInt("quantity");
			int toItem = res->getInt("itemid");

			ostringstream ss3;
			ss3 << "UPDATE `inventory` SET `itemid`='" << toItem << "', `quantity`='" << toQty << "' WHERE invid='" << fromID << "' AND charid=" << charid;
			NewQuery(stmt, ss3.str());

			ostringstream ss4;
			ss4 << "UPDATE `inventory` SET `itemid`='" << fromItem << "', `quantity`='" << fromQty << "' WHERE invid='" << toID << "' AND charid=" << charid;
			NewQuery(stmt, ss4.str());

			ostringstream ssi;
			ssi << fromQty << "n" << fromItem << "n" << toID << "n";
			struct QueuedItem ToSend1 = {ToReceive.ToID, "", "updateitem", "inventory", ssi.str(), 0, 0, 0};
			QueueToSend.push(ToSend1);

			ostringstream ssi2;
			ssi2 << toQty << "n" << toItem << "n" << fromID << "n";
			struct QueuedItem ToSend2 = {ToReceive.ToID, "", "updateitem", "inventory", ssi2.str(), 0, 0, 0};
			QueueToSend.push(ToSend2);

		// If 'to' is empty
		} else {

			ostringstream ss3;
			ss3 << "INSERT INTO `inventory` VALUES (" << fromItem << ", " << charid << ", " << fromQty << ", " << toID << ")";
			NewQuery(stmt, ss3.str());

			ostringstream ss4;
			ss4 << "DELETE FROM `inventory` WHERE `invid`='" << fromID << "' AND charid=" << charid;
			NewQuery(stmt, ss4.str());

			ostringstream ssi;
			ssi << fromQty << "n" << fromItem << "n" << toID << "n";
			struct QueuedItem ToSend1 = {ToReceive.ToID, "", "updateitem", "inventory", ssi.str(), 0, 0, 0};
			QueueToSend.push(ToSend1);

			ostringstream ssi2;
			ssi2 << 0 << "n" << 0 << "n" << fromID << "n";
			struct QueuedItem ToSend2 = {ToReceive.ToID, "", "updateitem", "inventory", ssi2.str(), 0, 0, 0};
			QueueToSend.push(ToSend2);
		}
	}

	// From inventory to equip (equip)
	if (fromType == 2 && toType == 1)
	{
		ostringstream ss0;
		ss0 << "SELECT * FROM `inventory` WHERE charid=" << charid << " AND invid=" << fromID;
		res = stmt->executeQuery(ss0.str());
		res->next();
		int fromItem = res->getInt("itemid");

		ostringstream ss1;
		ss1 << "SELECT equip, effects FROM `items` WHERE id=" << fromItem;
		res = stmt->executeQuery(ss1.str());
		if (res->next())
		{
			bool isAnEquip = res->getBoolean("equip");
			string equipType = res->getString("effects");

			if (isAnEquip)
			{
				bool isGood = false;

				if (equipType == equip[toID])
					isGood = true;

				if (equipType == "e_hand")
				{
					if ("e_hand1" == equip[toID])
					{
						equipType = "e_hand1";
						isGood = true;
					}

					if ("e_hand2" == equip[toID])
					{
						equipType = "e_hand2";
						isGood = true;
					}
				}

				if (equipType == "e_acc")
				{
					if ("e_acc1" == equip[toID])
					{
						equipType = "e_acc1";
						isGood = true;
					}

					if ("e_acc2" == equip[toID])
					{
						equipType = "e_acc2";
						isGood = true;
					}
				}

				if (isGood)
				{
					ostringstream ss5;
					ss5 << "SELECT " << equip[toID] << " FROM `char` WHERE islogged=" << ToReceive.ToID;
					res = stmt->executeQuery(ss5.str());
					res->next();

					int lastEquip = res->getInt(equip[toID]);

					// If there is not any equips yet..
					if (lastEquip == 0)
					{
						ostringstream ss3;
						ss3 << "DELETE FROM `inventory` WHERE `invid`='" << fromID << "' AND charid=" << charid;
						NewQuery(stmt, ss3.str());

						ostringstream ss4;
						ss4 << "UPDATE `char` SET `" << equip[toID] << "`='" << fromItem << "' WHERE id=" << charid;
						NewQuery(stmt, ss4.str());

						ostringstream ssi;
						ssi << "0n0n" << fromID << "n";
						struct QueuedItem ToSend1 = {ToReceive.ToID, "", "updateitem", "inventory", ssi.str(), 0, 0, 0};
						QueueToSend.push(ToSend1);

						ostringstream ssi2;
						ssi2 << toID << "n" << fromItem << "n";
						struct QueuedItem ToSend2 = {ToReceive.ToID, "", "updateitem", "equip", ssi2.str(), 0, 0, 0};
						QueueToSend.push(ToSend2);

					// If there is already one..
					} else {

						ostringstream ss3;
						ss3 << "UPDATE `inventory` SET `itemid`='" << lastEquip << "', `quantity`='1' WHERE invid='" << fromID << "'";
						NewQuery(stmt, ss3.str());

						ostringstream ss4;
						ss4 << "UPDATE `char` SET `" << equip[toID] << "`='" << fromItem << "' WHERE id=" << charid;
						NewQuery(stmt, ss4.str());

						ostringstream ssi;
						ssi << "1n" << lastEquip << "n" << fromID << "n";
						struct QueuedItem ToSend1 = {ToReceive.ToID, "", "updateitem", "inventory", ssi.str(), 0, 0, 0};
						QueueToSend.push(ToSend1);

						ostringstream ssi2;
						ssi2 << toID << "n" << fromItem << "n";
						struct QueuedItem ToSend2 = {ToReceive.ToID, "", "updateitem", "equip", ssi2.str(), 0, 0, 0};
						QueueToSend.push(ToSend2);
					}

					ostringstream ssc;
					ssc << "SELECT charname, x, y, islogged, e_head, e_body, party FROM `char` WHERE islogged>0 AND map='" << mapid << "'";
					res = stmt->executeQuery(ssc.str());
					while (res->next())
					{
						if (res->getInt("islogged") != ToReceive.ToID)
						{
							if (toID == 0)
							{
								struct QueuedItem ToSendEE = {res->getInt("islogged"), charname, "updateitemo", "equipall", "", fromItem, -1, 0};
								QueueToSend.push(ToSendEE);

							} else if (toID == 7)
							{
								struct QueuedItem ToSendEE = {res->getInt("islogged"), charname, "updateitemo", "equipall", "", -1, fromItem, 0};
								QueueToSend.push(ToSendEE);
							}
						}
					}
				}
			}
		}
	}

	// From equip to inventory (unequip)
	if (fromType == 1 && toType == 2)
	{
		ostringstream ss1;
		ss1 << "SELECT " << equip[fromID] << " FROM `char` WHERE id=" << charid;
		res = stmt->executeQuery(ss1.str());
		res->next();
		int fromItem = res->getInt(equip[fromID]);

		ostringstream ss2;
		ss2 << "SELECT * FROM `inventory` WHERE charid=" << charid << " AND invid=" << toID;
		res = stmt->executeQuery(ss2.str());
		if (!res->next())
		{
			ostringstream ss3;
			ss3 << "INSERT INTO `inventory` VALUES (" << fromItem << ", " << charid << ", " << 1 << ", " << toID << ")";
			NewQuery(stmt, ss3.str());

			ostringstream ss4;
			ss4 << "UPDATE `char` SET `" << equip[fromID] << "`=0 WHERE id=" << charid;
			NewQuery(stmt, ss4.str());

			ostringstream ssi;
			ssi << "1n" << fromItem << "n" << toID << "n";
			struct QueuedItem ToSend1 = {ToReceive.ToID, "", "updateitem", "inventory", ssi.str(), 0, 0, 0};
			QueueToSend.push(ToSend1);

			ostringstream ssi2;
			ssi2 << fromID << "n" << 0 << "n";
			struct QueuedItem ToSend2 = {ToReceive.ToID, "", "updateitem", "equip", ssi2.str(), 0, 0, 0};
			QueueToSend.push(ToSend2);

			ostringstream ssc;
			ssc << "SELECT charname, x, y, islogged, e_head, e_body, party FROM `char` WHERE islogged>0 AND map='" << mapid << "'";
			res = stmt->executeQuery(ssc.str());
			while (res->next())
			{
				if (res->getInt("islogged") != ToReceive.ToID)
				{
					if (fromID == 0)
					{
						struct QueuedItem ToSendEE = {res->getInt("islogged"), charname, "updateitemo", "equipall", "", 0, -1, 0};
						QueueToSend.push(ToSendEE);

					} else if (fromID == 7)
					{
						struct QueuedItem ToSendEE = {res->getInt("islogged"), charname, "updateitemo", "equipall", "", -1, 0, 0};
						QueueToSend.push(ToSendEE);
					}
				}
			}
		}
	}

	} catch (sql::SQLException &e) {
	  cout << "# ERR: SQLException in " << __FILE__;
	  cout << "(" << __FUNCTION__ << ") on line " 
		 << __LINE__ << endl;
	  cout << "# ERR: " << e.what();
	  cout << " (MySQL error code: " << e.getErrorCode();
	  cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}*/

// If a user disconnected
void Network::Disconnect(int id)
{
	ostringstream ss;
	ss << "UPDATE `user` SET islogged=0 WHERE islogged='" << id << "'";
	NewQuery(ss.str());
	
	if (m_charInfo[id].charname != "")
	{
		/*string charname = res->getString("charname");
		int map = res->getInt("map");
		string party = res->getString("party");
		
		// Send info to party members
		if (party != "-")
		{
			ostringstream ss4;
			ss4 << "SELECT islogged FROM `char` WHERE islogged>0 AND party='" << party << "'";
			res = stmt->executeQuery(ss4.str());
			while (res->next())
			{
				struct functions packetInformation = {res->getInt("islogged"), "party", "logout", charname};
				m_packetsToSend.push(packetInformation);
			}
		}*/

		ostringstream ss3;
		ss3 << "UPDATE `char` SET islogged=0, `x`='" << m_charInfo[id].x << "', `y`='" << m_charInfo[id].y << "', `map`='" << m_charInfo[id].map << "' WHERE islogged='" << id << "'";
		NewQuery(ss3.str());

		// Send info to players of the same map
		for(std::map<int, struct character>::const_iterator it = m_charInfo.begin(); it != m_charInfo.end(); ++it)
		{
			if (it->second.map == m_charInfo[id].map)
			{
				stringstream idstring;
				idstring << id;
				struct functions packetInformation = {m_charid[it->second.charname], "main", "charout", idstring.str()};
				m_packetsToSend.push(packetInformation);
			}
		}

		cout << "Character " << m_charInfo[id].charname << " disconnected. (ID " << id << ")" << endl;
		
	} else {

		cout << "Client number " << id << " has lost connection." << endl;
	}

	m_charid.erase(m_charInfo[id].charname);
	m_charInfo.erase(id);
}
